Skip to content

[refactor](storage) extract RowKeyEncoder: dedup key encoding across both segment writers#65492

Open
csun5285 wants to merge 7 commits into
apache:masterfrom
csun5285:refactor/row-key-encoder
Open

[refactor](storage) extract RowKeyEncoder: dedup key encoding across both segment writers#65492
csun5285 wants to merge 7 commits into
apache:masterfrom
csun5285:refactor/row-key-encoder

Conversation

@csun5285

@csun5285 csun5285 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Both writers now hold a RowKeyEncoder member and _generate_primary_key_index loses its coder parameter. BlockAggregator's calls into the writer's encode helpers in partial_update_info.cpp are redirected onto the writer's _key_encoder (decoupling BlockAggregator from the writer entirely is left to a follow-up).

What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@csun5285

Copy link
Copy Markdown
Contributor Author

run buildall

@csun5285

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed with one inline issue.

Critical checkpoint conclusions:

  • Goal/refactor: the RowKeyEncoder extraction preserves the old writer-local full-key, short-key, sequence-suffix, cluster-key primary-key separation, and rowid-suffix flows based on static comparison with GitHub base snapshots.
  • Scope: the production changes are focused in BE storage key/segment writer paths; I did not find another substantiated production correctness issue.
  • Concurrency/lifecycle: no new shared mutable state, thread entry, lock ordering, or special lifetime boundary was introduced by the helper; it stores schema-derived coder pointers like the old writers did.
  • Config/compatibility/persistence: no config, protocol, edit-log, or storage-format change was found; the encoded byte layout is covered by new unit-test goldens.
  • Parallel paths: SegmentWriter, VerticalSegmentWriter, and BlockAggregator call paths were checked, including cluster-key and sequence-column paths.
  • Tests/style: one test hygiene issue remains: the new unit test leaks private/protected macros into later includes.
  • User focus: no additional user-provided focus was present.

Validation was static only: this checkout is missing .worktree_initialized, thirdparty/installed, thirdparty/installed/bin/protoc, and clang-format v16, and the base commit is not present locally. I used GitHub PR metadata/base snapshots for diff scope. git show --check reported no whitespace errors on the changed files.

Subagent conclusions: tests-session-config proposed TSC-001, accepted as MAIN-001 and submitted inline. optimizer-rewrite found no candidates. Convergence round 1 ended with both live subagents returning NO_NEW_VALUABLE_FINDINGS for the final one-comment ledger set.

Comment thread be/test/storage/key/row_key_encoder_test.cpp Outdated
@csun5285

Copy link
Copy Markdown
Contributor Author

run buildall

@csun5285

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review summary:

I found one test-coverage issue in the new RowKeyEncoder unit test. The production refactor itself looks byte-compatible with the removed SegmentWriter/VerticalSegmentWriter helper logic after checking full-key, short-key, null, sequence, rowid, cluster-key MoW, partial-update reachability, min/max, and lookup-side consumers.

Critical checkpoint conclusions:

  • Goal/test proof: the refactor has focused unit coverage for marker layout, suffixes, short keys, and many key coders, but the cluster-key separation test does not prove the primary-vs-sort coder split.
  • Scope: the implementation is focused on extracting key encoding into RowKeyEncoder and replacing the writer-local helpers.
  • Concurrency/lifecycle/config/persistence/FE-BE protocol: no new concurrency, dynamic config, persistence format, or protocol surface was introduced.
  • Parallel paths: SegmentWriter and VerticalSegmentWriter were both updated; partial-update and lookup-side paths were checked for compatibility.
  • Data correctness: no production key byte-layout or accessor-routing bug was substantiated.
  • Tests: one targeted test needs strengthening; no build/tests were run because the review prompt explicitly restricts this task to review operations.
  • User focus: no additional user-provided review focus was supplied.


// With cluster keys the segment sorts by the cluster key columns, while the
// primary key index is still built over the schema key columns.
TEST_F(RowKeyEncoderTest, ClusterKeySortDiffersFromPrimaryKeys) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test does not actually catch the primary-vs-cluster coder mixup that the refactor is trying to protect against. cluster_key_schema() makes both the primary key and the cluster key INT columns, and this assertion only proves that encoded value 5 differs from encoded value 99. If full_encode_primary_keys() accidentally used the cluster/sort-key coder vector, the test would still pass because the supplied primary-key accessor is also INT. Please make this case heterogeneous, for example INT primary key plus CHAR/VARCHAR cluster key, and assert the exact hex for full_encode_primary_keys(primary_keys), full_encode(sort_keys), and the short key so a wrong coder vector fails deterministically.

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 95.24% (120/126) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 73.18% (29544/40369)
Line Coverage 56.82% (320356/563774)
Region Coverage 53.24% (266414/500426)
Branch Coverage 54.27% (117392/216307)

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29969 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 8802f5ea042363d0a60ff6ae4dda678f57a25fe4, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17680	4305	4125	4125
q2	2062	324	209	209
q3	10265	1432	842	842
q4	4679	525	340	340
q5	7503	871	594	594
q6	188	171	138	138
q7	777	856	622	622
q8	9346	1638	1603	1603
q9	5686	4438	4442	4438
q10	6778	1813	1546	1546
q11	494	345	317	317
q12	705	541	439	439
q13	18109	3373	2764	2764
q14	269	259	240	240
q15	q16	789	780	712	712
q17	938	982	958	958
q18	7012	5770	5749	5749
q19	1331	1310	1057	1057
q20	740	658	525	525
q21	5970	2587	2450	2450
q22	436	356	301	301
Total cold run time: 101757 ms
Total hot run time: 29969 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4364	4299	4254	4254
q2	286	312	214	214
q3	4565	4932	4401	4401
q4	2054	2092	1385	1385
q5	4531	4314	4362	4314
q6	231	170	129	129
q7	1713	2127	1771	1771
q8	2564	2247	2163	2163
q9	8328	8252	7962	7962
q10	4775	4733	4257	4257
q11	598	417	380	380
q12	759	775	540	540
q13	3315	3577	2863	2863
q14	307	315	265	265
q15	q16	700	736	651	651
q17	1324	1321	1427	1321
q18	7769	7233	7432	7233
q19	1142	1109	1072	1072
q20	2198	2202	1929	1929
q21	5230	4500	4372	4372
q22	518	449	420	420
Total cold run time: 57271 ms
Total hot run time: 51896 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 180905 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 8802f5ea042363d0a60ff6ae4dda678f57a25fe4, data reload: false

query5	4310	651	483	483
query6	455	233	204	204
query7	4851	564	329	329
query8	335	187	192	187
query9	8772	4109	4074	4074
query10	478	345	296	296
query11	5933	2376	2149	2149
query12	156	103	100	100
query13	1247	603	453	453
query14	6210	5313	4951	4951
query14_1	4312	4266	4317	4266
query15	216	222	178	178
query16	1002	497	453	453
query17	955	741	618	618
query18	2437	477	353	353
query19	211	209	158	158
query20	114	109	107	107
query21	232	160	132	132
query22	13686	13594	13404	13404
query23	17344	16601	16208	16208
query23_1	16309	16192	16217	16192
query24	7636	1775	1323	1323
query24_1	1349	1340	1295	1295
query25	571	477	405	405
query26	1322	369	215	215
query27	2672	609	374	374
query28	4407	2036	2044	2036
query29	1094	641	502	502
query30	344	268	229	229
query31	1111	1102	992	992
query32	109	64	62	62
query33	526	325	270	270
query34	1204	1159	689	689
query35	785	779	685	685
query36	1375	1353	1227	1227
query37	161	111	97	97
query38	1893	1705	1665	1665
query39	917	905	899	899
query39_1	877	870	882	870
query40	245	174	139	139
query41	67	63	63	63
query42	92	90	91	90
query43	327	336	277	277
query44	1419	806	780	780
query45	203	190	179	179
query46	1086	1254	744	744
query47	2425	2344	2226	2226
query48	406	400	307	307
query49	571	430	312	312
query50	1038	433	333	333
query51	10822	10769	10688	10688
query52	92	87	75	75
query53	276	284	199	199
query54	281	258	224	224
query55	81	76	67	67
query56	285	318	286	286
query57	1445	1419	1325	1325
query58	303	311	253	253
query59	1610	1644	1427	1427
query60	304	275	254	254
query61	151	146	157	146
query62	696	651	592	592
query63	241	208	209	208
query64	2859	1059	865	865
query65	4871	4787	4981	4787
query66	1825	516	393	393
query67	29435	29328	29309	29309
query68	3020	1541	978	978
query69	400	312	271	271
query70	1093	942	961	942
query71	356	329	310	310
query72	3099	2774	2479	2479
query73	830	795	436	436
query74	5093	4964	4774	4774
query75	2626	2602	2218	2218
query76	2315	1209	813	813
query77	366	388	289	289
query78	12393	12294	11804	11804
query79	1431	1144	781	781
query80	1284	547	456	456
query81	549	323	283	283
query82	607	159	120	120
query83	387	321	299	299
query84	329	158	130	130
query85	949	611	526	526
query86	416	301	291	291
query87	1830	1832	1742	1742
query88	3737	2837	2807	2807
query89	453	417	361	361
query90	1923	207	196	196
query91	199	191	160	160
query92	64	57	58	57
query93	1755	1549	964	964
query94	719	363	310	310
query95	785	489	495	489
query96	1099	834	361	361
query97	2705	2677	2557	2557
query98	213	210	202	202
query99	1162	1189	1024	1024
Total cold run time: 265853 ms
Total hot run time: 180905 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.22 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 8802f5ea042363d0a60ff6ae4dda678f57a25fe4, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.05	0.04
query3	0.25	0.14	0.13
query4	1.61	0.13	0.14
query5	0.25	0.27	0.24
query6	1.26	1.08	1.11
query7	0.04	0.01	0.01
query8	0.05	0.04	0.04
query9	0.39	0.32	0.32
query10	0.57	0.59	0.59
query11	0.20	0.15	0.14
query12	0.18	0.15	0.14
query13	0.48	0.47	0.49
query14	1.01	1.02	1.02
query15	0.62	0.63	0.60
query16	0.33	0.34	0.33
query17	1.12	1.09	1.15
query18	0.23	0.21	0.21
query19	2.01	1.94	2.01
query20	0.02	0.02	0.02
query21	15.45	0.23	0.13
query22	4.82	0.06	0.05
query23	16.11	0.32	0.12
query24	2.95	0.44	0.32
query25	0.11	0.05	0.05
query26	0.75	0.21	0.14
query27	0.05	0.04	0.04
query28	3.49	0.97	0.57
query29	12.48	4.11	3.26
query30	0.28	0.15	0.14
query31	2.77	0.61	0.30
query32	3.21	0.59	0.48
query33	3.11	3.17	3.20
query34	15.48	4.22	3.55
query35	3.52	3.56	3.56
query36	0.56	0.44	0.45
query37	0.09	0.06	0.06
query38	0.05	0.04	0.04
query39	0.03	0.03	0.03
query40	0.18	0.16	0.15
query41	0.09	0.03	0.02
query42	0.04	0.02	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.39 s
Total hot run time: 25.22 s

@csun5285

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed with no new inline issues.

Critical checkpoint conclusions:

  • Goal/test proof: the RowKeyEncoder extraction centralizes the former writer-local key encoding while preserving full-key, short-key, primary-key, sequence-suffix, and rowid-suffix behavior. The expanded BE unit test/golden now covers primary-vs-cluster key views, all current default-converted key types, null ordering, short-key truncation, sequence suffixes, and rowid suffix boundaries.
  • Scope: the implementation is focused on BE storage key encoding and the horizontal/vertical segment-writer call sites.
  • Data correctness: no reachable primary-key-vs-cluster-key accessor mismatch was substantiated. Normal MOW cluster-key writers use full_encode_primary_keys() for primary-index entries and rebuild cluster-key accessors for short/min/max keys; partial-update paths that would be suspicious are guarded before flush for MOW cluster-key partial updates.
  • Concurrency/lifecycle: no new shared mutable state, thread entry, lock ordering, or special lifetime boundary was introduced.
  • Config/compatibility/persistence/protocol: no dynamic config, edit-log, storage-format, or FE/BE protocol change was introduced. Reader and delete-bitmap consumers still strip/decode the same sequence and rowid suffix lengths.
  • Parallel paths: SegmentWriter, VerticalSegmentWriter, BlockAggregator partial-update paths, primary-index readers, and delete-bitmap calculator paths were reviewed.
  • Tests/style: the two existing review threads appear addressed in the current head: the white-box macros are scoped to the intended include, and the primary-vs-cluster test now uses heterogeneous/reordered views plus byte-level goldens.
  • User focus: no additional user-provided review focus was present.

Subagent conclusions: Round 1 Subagent A (production writer), Subagent B (test/golden), and Risk Subagent C (key-view/suffix reachability) all returned NO_NEW_VALUABLE_FINDINGS; the main risk items R1-R3 were dismissed with code evidence.

Validation was static only. I did not run builds or tests because the review prompt explicitly forbids builds in this review environment.

@csun5285

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29625 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 29675bfeb39e5b4005c97185164c987506656a3e, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17650	4193	4108	4108
q2	2071	320	204	204
q3	10297	1398	841	841
q4	4684	478	342	342
q5	7550	855	569	569
q6	186	171	140	140
q7	780	822	629	629
q8	9349	1417	1642	1417
q9	5571	4357	4353	4353
q10	6867	1724	1509	1509
q11	519	339	310	310
q12	703	554	434	434
q13	18149	3504	2771	2771
q14	284	265	251	251
q15	q16	792	788	720	720
q17	913	968	1008	968
q18	7008	5836	5494	5494
q19	1263	1270	1068	1068
q20	794	657	530	530
q21	6183	2897	2640	2640
q22	474	372	327	327
Total cold run time: 102087 ms
Total hot run time: 29625 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5121	4996	4976	4976
q2	308	334	219	219
q3	4906	5342	4756	4756
q4	2104	2145	1403	1403
q5	4804	4712	4636	4636
q6	229	185	128	128
q7	1885	1791	1530	1530
q8	2405	2090	2104	2090
q9	7759	7204	7123	7123
q10	4607	4574	4141	4141
q11	531	387	353	353
q12	725	748	548	548
q13	2986	3390	2795	2795
q14	294	273	265	265
q15	q16	678	694	607	607
q17	1289	1242	1242	1242
q18	7327	6791	6722	6722
q19	1065	1058	1049	1049
q20	2225	2235	1943	1943
q21	5238	4566	4418	4418
q22	503	449	389	389
Total cold run time: 56989 ms
Total hot run time: 51333 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 178552 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 29675bfeb39e5b4005c97185164c987506656a3e, data reload: false

query5	4325	647	475	475
query6	492	218	200	200
query7	4904	591	340	340
query8	343	182	169	169
query9	8756	4066	4071	4066
query10	466	393	300	300
query11	5890	2341	2195	2195
query12	162	105	101	101
query13	1256	604	454	454
query14	6263	5218	4877	4877
query14_1	4287	4233	4245	4233
query15	207	200	179	179
query16	1010	483	430	430
query17	954	756	572	572
query18	2503	503	356	356
query19	210	194	153	153
query20	115	113	108	108
query21	229	159	134	134
query22	13646	13506	13361	13361
query23	17354	16391	16047	16047
query23_1	16246	16303	16213	16213
query24	7601	1759	1291	1291
query24_1	1316	1290	1268	1268
query25	561	463	379	379
query26	1351	344	214	214
query27	2645	572	387	387
query28	4450	2025	1983	1983
query29	1102	634	510	510
query30	342	265	235	235
query31	1132	1088	972	972
query32	101	66	61	61
query33	523	324	267	267
query34	1165	1122	646	646
query35	778	786	671	671
query36	1225	1193	1054	1054
query37	153	100	90	90
query38	1877	1696	1702	1696
query39	886	850	847	847
query39_1	818	835	856	835
query40	250	158	134	134
query41	64	63	64	63
query42	90	89	89	89
query43	319	325	288	288
query44	1409	779	776	776
query45	197	177	175	175
query46	1084	1179	725	725
query47	2107	2146	1979	1979
query48	391	382	314	314
query49	599	415	306	306
query50	1035	430	334	334
query51	10953	10781	10558	10558
query52	85	89	74	74
query53	263	270	198	198
query54	275	223	222	222
query55	78	73	68	68
query56	289	292	284	284
query57	1310	1290	1194	1194
query58	286	243	256	243
query59	1569	1628	1432	1432
query60	306	265	248	248
query61	151	149	154	149
query62	545	486	428	428
query63	237	203	197	197
query64	2795	1076	851	851
query65	4699	4652	4640	4640
query66	1883	505	370	370
query67	29342	29172	29093	29093
query68	3185	1474	1010	1010
query69	408	303	251	251
query70	1031	987	976	976
query71	378	318	292	292
query72	3215	2687	2392	2392
query73	839	772	418	418
query74	5059	4906	4731	4731
query75	2526	2495	2123	2123
query76	2317	1183	759	759
query77	347	374	285	285
query78	11869	11727	11320	11320
query79	1381	1153	764	764
query80	767	530	442	442
query81	486	316	272	272
query82	582	153	122	122
query83	402	317	288	288
query84	326	157	132	132
query85	962	589	511	511
query86	403	292	265	265
query87	1859	1818	1766	1766
query88	3674	2814	2783	2783
query89	428	378	319	319
query90	1852	200	196	196
query91	195	185	159	159
query92	63	62	55	55
query93	1514	1554	1022	1022
query94	622	366	323	323
query95	780	477	475	475
query96	1066	804	360	360
query97	2680	2640	2491	2491
query98	219	203	200	200
query99	1088	1101	979	979
Total cold run time: 263178 ms
Total hot run time: 178552 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.91 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 29675bfeb39e5b4005c97185164c987506656a3e, data reload: false

query1	0.01	0.00	0.01
query2	0.09	0.05	0.05
query3	0.25	0.14	0.13
query4	1.62	0.17	0.14
query5	0.24	0.22	0.22
query6	1.26	1.05	1.08
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.39	0.33	0.31
query10	0.55	0.55	0.59
query11	0.21	0.14	0.14
query12	0.17	0.14	0.14
query13	0.47	0.48	0.47
query14	1.02	1.03	1.00
query15	0.61	0.58	0.59
query16	0.33	0.34	0.30
query17	1.09	1.11	1.11
query18	0.22	0.21	0.21
query19	2.00	1.91	1.90
query20	0.01	0.02	0.01
query21	15.45	0.20	0.13
query22	4.93	0.05	0.05
query23	16.15	0.31	0.13
query24	2.90	0.44	0.33
query25	0.11	0.04	0.04
query26	0.73	0.20	0.16
query27	0.05	0.03	0.03
query28	3.59	0.89	0.52
query29	12.51	3.99	3.18
query30	0.29	0.16	0.15
query31	2.77	0.60	0.31
query32	3.22	0.60	0.48
query33	3.16	3.23	3.16
query34	15.68	4.28	3.57
query35	3.53	3.53	3.52
query36	0.56	0.43	0.44
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.03	0.02	0.02
query40	0.18	0.17	0.16
query41	0.09	0.03	0.02
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.79 s
Total hot run time: 24.91 s

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wkeyword-macro"
#endif
#define private public

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These macros are unnecessary: doris_be_test is already compiled with -fno-access-control in be/test/CMakeLists.txt, so this test can access TabletSchema private fields directly. Keeping private/protected redefined while including tablet_schema.h also rewrites access specifiers in its transitive protobuf, phmap, and Doris headers, which can make this translation unit class definitions differ from other TUs. Please remove the pragma/macro block and include tablet_schema.h normally.

bobhan1
bobhan1 previously approved these changes Jul 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Jul 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

Comment thread be/src/storage/key/row_key_encoder.cpp Outdated

RowKeyEncoder::RowKeyEncoder(const TabletSchema& schema, bool mow) {
for (size_t cid = 0; cid < schema.num_key_columns(); ++cid) {
_primary_key_coders.push_back(get_key_coder(schema.column(cid).type()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_primary_key_coders 和 _seq_coder 看着只有mow表才会,是不mow和非mow分别弄个函数实现的。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

// 6. Compare all encoded views with the generated byte-level snapshot.
// Refresh this snapshot with:
// ./run-be-ut.sh --run --filter=RowKeyEncoderTest.AllKeyTypesTable --gen_out -j 64
const char* root = std::getenv("ROOT");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need ROOT env ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes,run-be-ut.sh 会把 ROOT 稳定设置为仓库根目录,这样无论在哪里运行这个UT 都是OK的

csun5285 added a commit to csun5285/doris that referenced this pull request Jul 15, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65492

Problem Summary: RowKeyEncoder initialized primary-key and sequence coders for table shapes whose writer paths never use them, and the table-driven test exercised primary-index encoding for non-MOW schemas. Split initialization by table mode, keep the separate primary-key and rowid view only for MOW cluster-key tables, and align the test with the SegmentWriter and VerticalSegmentWriter call paths. Regenerate the golden so non-MOW rows report the inapplicable primary-index key as N/A while preserving every MOW encoded key byte.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-be-ut.sh --run --filter=RowKeyEncoderTest.* -j64 (3 tests passed)
    - build-support/check-format.sh (passed with clang-format 16)
    - build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN (0 warnings)
- Behavior changed: No
- Does this need documentation: No
@github-actions github-actions Bot removed the approved Indicates a PR has been approved by one committer. label Jul 15, 2026
@csun5285

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed with one requested test-coverage fix.

Critical checkpoint conclusions:

  • Goal fit: the RowKeyEncoder extraction preserves the intended source behavior in the reviewed writer paths, but the new golden coverage misses a supported cluster-key shape central to this refactor.
  • Scope/focus: the implementation is narrowly scoped to storage key encoding and writer call-site cleanup.
  • Concurrency/lifecycle: no new shared mutable concurrency, lock ordering, static initialization, or ownership lifecycle issue was found.
  • Compatibility/persistence/config: no storage-format, EditLog, FE/BE protocol, or config compatibility change was introduced.
  • Parallel paths: SegmentWriter and VerticalSegmentWriter were both updated; MoW cluster-key partial update remains rejected before segment writing, while normal UPSERT uses the primary and cluster key views on the correct paths.
  • Tests: existing tests cover byte layout for many types and suffixes, but they still miss cluster-key schemas where primary-key and sort-key accessor counts differ.

User focus: no additional user-provided focus points were supplied.

Validation: static review only, per the review prompt. I did not run builds or tests in this review-only runner.

Comment thread be/test/storage/key/row_key_encoder_test.cpp
csun5285 added a commit to csun5285/doris that referenced this pull request Jul 15, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65492

Problem Summary: The RowKeyEncoder golden matrix used equal primary-key and cluster-key accessor counts, so it did not prove that each encoding view consumes its own accessor set. Add a merge-on-write cluster-key case with one primary key, four cluster keys, and a two-column short-key prefix, and pin the full sort key, primary key, short key, and primary-index key bytes.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-be-ut.sh --run --filter=RowKeyEncoderTest.* -j64 (3 tests passed)
    - build-support/check-format.sh (passed with clang-format 16)
    - build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN (0 warnings)
- Behavior changed: No
- Does this need documentation: No
csun5285 and others added 7 commits July 15, 2026 12:01
…both segment writers

SegmentWriter and VerticalSegmentWriter carry two verbatim copies of the
row-key encoding logic (_full_encode_keys x2, _encode_seq_column,
_encode_rowid, _encode_keys, plus six coder members each). Extract it into
a shared RowKeyEncoder (be/src/storage/key/row_key_encoder.{h,cpp}) with
the two views made explicit:

- full_encode() / encode_short_keys(): the sort-key view (cluster key
  columns for mow tables with cluster keys, schema key columns otherwise)
- full_encode_primary_keys(): the primary-key view (always the schema key
  columns; the primary key index is built on these even when the segment
  sorts by cluster keys)
- append_seq_suffix() / append_rowid_suffix(): the two key suffixes

Both writers now hold a RowKeyEncoder member and _generate_primary_key_index
loses its coder parameter. BlockAggregator's calls into the writer's encode
helpers in partial_update_info.cpp are redirected onto the writer's
_key_encoder (decoupling BlockAggregator from the writer entirely is left
to a follow-up).

Equivalence notes for review:
- SegmentWriter's _full_encode_keys had a null_first parameter that no
  caller ever set to false; the encoder always uses the null-first marker.
- The constructor DCHECK(num_sort_key_columns >= num_short_key_columns) is
  dropped; both counts now derive from TabletSchema in one place.
- SegmentWriter::set_mow_context had zero callers and is removed.
- _maybe_invalid_row_cache intentionally stays in the writers; moving the
  row-cache invalidation is out of scope here.

Tests: row_key_encoder_test.cpp with 30 cases - 13 behavior cases (marker
layout, null-first ordering, sort-key vs primary-key views, short-key
truncation and collision, seq/rowid suffixes) plus a golden byte matrix
that pins the encoded bytes of every legal key-column type (TINYINT,
SMALLINT, INT, BIGINT, LARGEINT, BOOL, DATEV2, DATETIMEV2, DECIMAL32/64/
128I/256, IPV4, IPV6, CHAR, VARCHAR, STRING) in all three views as literal
hex strings, so any coder change or CPU-architecture drift fails loudly.
Every existing MoW / partial-update / pk-index UT now executes through
RowKeyEncoder.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… only

Address review: the white-box macros were defined before every include of
the test TU, so gtest, standard and other Doris headers were all parsed
with rewritten access specifiers. Wrap only storage/tablet/tablet_schema.h
(the one header the test needs white-box access to) and #undef right after,
following the convention of segment_iterator_limit_opt_test.cpp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TIMESTAMPTZ is a legal key column type (the FE key-type blacklist does not
exclude it) with its own registered key coder (raw big-endian uint64), so
the golden byte matrix must pin it like the other key types.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
### What problem does this PR solve?

Issue Number: None

Related PR: apache#64674

Problem Summary: The existing RowKeyEncoder tests spread byte-layout and ordering assertions across 31 narrow cases, making it difficult to verify every production schema path consistently. Consolidate them into one explicit 51-row table spanning all 17 current key types and eight valid schema shapes, add data-driven sequence and rowid suffix coverage, and pin every encoded view in an auto-generated golden file. This keeps behavior unchanged while making sort-key, primary-key, short-key, null, sequence, and rowid contracts reviewable from a single dataset.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-be-ut.sh --run --filter=RowKeyEncoderTest.* -j64 (3 tests passed)
    - ./run-be-ut.sh --run --filter=RowKeyEncoderTest.AllKeyTypesTable --gen_out -j64 (golden regenerated)
    - build-support/check-format.sh (passed with clang-format 16)
    - build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN (0 warnings)
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#64674

Problem Summary: The data-driven RowKeyEncoder table test used golden-prefixed names for runtime result columns and lacked clear structure across its validation phases. Rename the result containers to describe their contents, remove the redundant fixed-size assertion, and divide the test into six documented stages. The test behavior and generated snapshot remain unchanged.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-be-ut.sh --run --filter=RowKeyEncoderTest.AllKeyTypesTable -j64 (1 test passed)
    - build-support/check-format.sh (passed with clang-format 16)
    - build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN (0 warnings)
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65492

Problem Summary: RowKeyEncoder initialized primary-key and sequence coders for table shapes whose writer paths never use them, and the table-driven test exercised primary-index encoding for non-MOW schemas. Split initialization by table mode, keep the separate primary-key and rowid view only for MOW cluster-key tables, and align the test with the SegmentWriter and VerticalSegmentWriter call paths. Regenerate the golden so non-MOW rows report the inapplicable primary-index key as N/A while preserving every MOW encoded key byte.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-be-ut.sh --run --filter=RowKeyEncoderTest.* -j64 (3 tests passed)
    - build-support/check-format.sh (passed with clang-format 16)
    - build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN (0 warnings)
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65492

Problem Summary: The RowKeyEncoder golden matrix used equal primary-key and cluster-key accessor counts, so it did not prove that each encoding view consumes its own accessor set. Add a merge-on-write cluster-key case with one primary key, four cluster keys, and a two-column short-key prefix, and pin the full sort key, primary key, short key, and primary-index key bytes.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-be-ut.sh --run --filter=RowKeyEncoderTest.* -j64 (3 tests passed)
    - build-support/check-format.sh (passed with clang-format 16)
    - build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN (0 warnings)
- Behavior changed: No
- Does this need documentation: No
@csun5285 csun5285 force-pushed the refactor/row-key-encoder branch from 2219644 to e7ecad0 Compare July 15, 2026 04:16
@csun5285

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completed a static review of this RowKeyEncoder refactor and did not find any new inline findings to add.

Checkpoint conclusions:

  • Goal and scope: the change is focused on deduplicating segment-writer key encoding behind RowKeyEncoder; the normal non-vertical and vertical writer paths still use the primary-key view for cluster-key MoW primary indexes and the sort/cluster-key view for short/min/max keys.
  • MoW and data correctness: I rechecked the suspicious partial-update path. The local writer code would be unsafe if cluster-key MoW partial update were allowed, but supported FE paths reject or disable that mode and BE MemTable::_to_block() rejects it before segment writing, so I am not leaving an inline comment for that dormant path.
  • Storage-format compatibility: sequence suffix, rowid suffix, primary-index key, short-key, and min/max byte layout match the removed writer-local helper behavior.
  • Parallel paths: both SegmentWriter and VerticalSegmentWriter were checked, along with direct-writer bypasses and lookup-side suffix parsing.
  • Tests and build integration: the new helper source and BE UT are covered by existing CMake globs, and the generated expected output now covers the primary/cluster/short-key split including mismatched counts. Existing review threads already covered the earlier test-only gaps, so I avoided duplicating them.
  • Concurrency, lifecycle, config, FE-BE protocol, persistence, and observability: I did not see new concerns in these categories for this refactor.

Validation was static only; I did not run builds or tests, consistent with the review bundle instructions.

@csun5285

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29402 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit e7ecad0702630a7ceb66537234562de95a7faebe, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17854	4368	4200	4200
q2	2030	314	201	201
q3	10306	1438	841	841
q4	4685	477	336	336
q5	7490	842	569	569
q6	194	175	140	140
q7	765	810	614	614
q8	9815	1524	1464	1464
q9	5954	4329	4341	4329
q10	6877	1771	1480	1480
q11	507	337	311	311
q12	728	554	433	433
q13	18180	3373	2747	2747
q14	273	256	245	245
q15	q16	806	779	713	713
q17	1132	1027	1000	1000
q18	6952	5785	5484	5484
q19	1459	1273	1011	1011
q20	755	626	557	557
q21	5773	2565	2429	2429
q22	432	362	298	298
Total cold run time: 102967 ms
Total hot run time: 29402 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4541	4441	4406	4406
q2	292	315	207	207
q3	4613	4905	4413	4413
q4	2101	2147	1395	1395
q5	4452	4326	4314	4314
q6	232	174	130	130
q7	2057	1991	1594	1594
q8	2596	2274	2213	2213
q9	7919	7827	7829	7827
q10	4657	4623	4193	4193
q11	575	425	492	425
q12	780	778	567	567
q13	3315	3636	2982	2982
q14	301	296	272	272
q15	q16	704	739	645	645
q17	1374	1358	1358	1358
q18	8290	7423	6761	6761
q19	1088	1045	1029	1029
q20	2237	2198	1917	1917
q21	5330	4716	4481	4481
q22	527	460	396	396
Total cold run time: 57981 ms
Total hot run time: 51525 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177213 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit e7ecad0702630a7ceb66537234562de95a7faebe, data reload: false

query5	4329	620	486	486
query6	465	215	204	204
query7	4840	609	337	337
query8	338	185	172	172
query9	8793	4073	4053	4053
query10	484	345	293	293
query11	5881	2325	2118	2118
query12	167	102	103	102
query13	1274	631	440	440
query14	6263	5214	4921	4921
query14_1	4251	4259	4234	4234
query15	218	207	176	176
query16	1030	457	408	408
query17	1126	728	590	590
query18	2504	461	341	341
query19	195	178	140	140
query20	108	107	107	107
query21	231	155	131	131
query22	13540	13558	13310	13310
query23	17190	16411	16072	16072
query23_1	16150	16185	16069	16069
query24	7635	1708	1291	1291
query24_1	1280	1257	1274	1257
query25	529	431	347	347
query26	1326	333	207	207
query27	2651	625	386	386
query28	4472	1984	1979	1979
query29	1065	590	475	475
query30	339	257	224	224
query31	1114	1083	964	964
query32	106	60	57	57
query33	523	320	245	245
query34	1162	1146	652	652
query35	776	783	666	666
query36	1222	1170	1035	1035
query37	154	101	87	87
query38	1876	1707	1646	1646
query39	873	874	842	842
query39_1	828	820	853	820
query40	247	157	132	132
query41	74	75	76	75
query42	90	90	91	90
query43	315	318	276	276
query44	1440	775	780	775
query45	197	188	170	170
query46	1017	1212	726	726
query47	2084	2091	2000	2000
query48	398	406	297	297
query49	586	418	310	310
query50	1017	432	329	329
query51	10950	10438	10689	10438
query52	82	85	70	70
query53	267	273	195	195
query54	290	226	209	209
query55	75	74	65	65
query56	293	277	271	271
query57	1322	1304	1216	1216
query58	291	267	257	257
query59	1555	1616	1433	1433
query60	298	271	250	250
query61	155	151	151	151
query62	553	492	420	420
query63	237	200	197	197
query64	2806	1019	815	815
query65	4626	4590	4620	4590
query66	1840	507	396	396
query67	29159	29106	28978	28978
query68	3235	1540	925	925
query69	427	359	256	256
query70	1033	934	953	934
query71	343	331	294	294
query72	2998	2648	2384	2384
query73	866	782	444	444
query74	5065	4889	4708	4708
query75	2522	2478	2107	2107
query76	2343	1177	777	777
query77	341	367	277	277
query78	11759	11812	11415	11415
query79	1207	1138	728	728
query80	609	538	443	443
query81	450	325	288	288
query82	236	154	120	120
query83	312	318	299	299
query84	282	154	127	127
query85	885	577	505	505
query86	313	286	282	282
query87	1813	1815	1781	1781
query88	3740	2780	2767	2767
query89	412	374	322	322
query90	2199	196	203	196
query91	201	188	161	161
query92	62	61	60	60
query93	1581	1483	971	971
query94	528	360	324	324
query95	775	575	471	471
query96	1085	832	359	359
query97	2610	2590	2507	2507
query98	208	208	206	206
query99	1089	1101	987	987
Total cold run time: 261365 ms
Total hot run time: 177213 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.95 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit e7ecad0702630a7ceb66537234562de95a7faebe, data reload: false

query1	0.01	0.00	0.01
query2	0.10	0.05	0.05
query3	0.25	0.13	0.13
query4	1.60	0.14	0.14
query5	0.27	0.23	0.22
query6	1.28	1.06	1.08
query7	0.04	0.00	0.00
query8	0.05	0.04	0.03
query9	0.39	0.31	0.30
query10	0.54	0.56	0.56
query11	0.20	0.15	0.14
query12	0.17	0.14	0.14
query13	0.46	0.48	0.48
query14	1.01	1.00	1.00
query15	0.62	0.60	0.59
query16	0.32	0.31	0.31
query17	1.12	1.11	1.14
query18	0.23	0.21	0.22
query19	1.98	1.92	1.95
query20	0.02	0.01	0.01
query21	15.47	0.24	0.13
query22	4.80	0.06	0.05
query23	16.12	0.31	0.12
query24	2.99	0.46	0.35
query25	0.12	0.05	0.04
query26	0.72	0.20	0.15
query27	0.04	0.03	0.02
query28	3.53	0.97	0.55
query29	12.48	4.15	3.23
query30	0.27	0.15	0.16
query31	2.79	0.64	0.31
query32	3.22	0.62	0.48
query33	3.12	3.26	3.19
query34	15.60	4.46	3.52
query35	3.52	3.49	3.47
query36	0.54	0.43	0.43
query37	0.08	0.07	0.06
query38	0.06	0.04	0.03
query39	0.04	0.02	0.02
query40	0.18	0.16	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.51 s
Total hot run time: 24.95 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 78.99% (109/138) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 57.22% (23809/41606)
Line Coverage 40.97% (233876/570894)
Region Coverage 36.82% (184689/501622)
Branch Coverage 37.91% (82695/218107)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 95.65% (132/138) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.82% (30366/40585)
Line Coverage 58.97% (334532/567286)
Region Coverage 55.60% (279941/503473)
Branch Coverage 56.89% (124123/218177)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 95.65% (132/138) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.82% (30366/40585)
Line Coverage 58.97% (334504/567286)
Region Coverage 55.63% (280070/503473)
Branch Coverage 56.94% (124235/218177)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants